// *************************************************************************************************
//
// Actual revision: $Revision: $
// Revision label:  $Name: $
// Revision state:  $State: $
//
// *************************************************************************************************
// Radio core access functions. Taken from TI reference code for CC430.
// *************************************************************************************************

// *************************************************************************************************
// Include section

// system
#include <project.h>

// driver
#include "rf1a.h"

// *************************************************************************************************
// Global section

// *************************************************************************************************
// Define section
#define st(x)                                           do { x } while (__LINE__ == -1)
#define ENTER_CRITICAL_SECTION(x)       st(x = __get_interrupt_state(); __disable_interrupt(); )
#define EXIT_CRITICAL_SECTION(x)    __set_interrupt_state(x)

// *************************************************************************************************
// @fn          Strobe
// @brief       Send command to radio.
// @param       unsigned char strobe    Command to radio
// @return      statusByte                              Radio core status
// *************************************************************************************************
unsigned char Strobe(unsigned char strobe)
{
    u8 statusByte = 0;
    u16 int_state, gdo_state;

    // Check for valid strobe command
    if ((strobe == 0xBD) || ((strobe > RF_SRES) && (strobe < RF_SNOP)))
    {
        ENTER_CRITICAL_SECTION(int_state);

        // Clear the Status read flag
        RF1AIFCTL1 &= ~(RFSTATIFG);

        // Wait for radio to be ready for next instruction
        while (!(RF1AIFCTL1 & RFINSTRIFG)) ;

        // Write the strobe instruction
        if ((strobe > RF_SRES) && (strobe < RF_SNOP))
        {

            gdo_state = ReadSingleReg(IOCFG2);         // buffer IOCFG2 state
            WriteSingleReg(IOCFG2, 0x29);              // c-ready to GDO2

            RF1AINSTRB = strobe;
            if ((RF1AIN & 0x04) == 0x04)               // chip at sleep mode
            {
                if ((strobe == RF_SXOFF) || (strobe == RF_SPWD) || (strobe == RF_SWOR))
                {
                }
                else
                {
                    while ((RF1AIN & 0x04) == 0x04) ;  // c-ready ?
                    __delay_cycles(9800);              // Delay for ~810usec at 12MHz CPU clock
                }
            }
            WriteSingleReg(IOCFG2, gdo_state);         // restore IOCFG2 setting
        }
        else                                           // chip active mode
        {
            RF1AINSTRB = strobe;
        }
        statusByte = RF1ASTATB;
        while (!(RF1AIFCTL1 & RFSTATIFG)) ;
        EXIT_CRITICAL_SECTION(int_state);
    }
    return statusByte;
}

// *************************************************************************************************
// @fn          ResetRadioCore
// @brief       Software reset radio core.
// @param       none
// @return      none
// *************************************************************************************************
void ResetRadioCore(void)
{
    Strobe(RF_SRES);            // Reset the Radio Core
    Strobe(RF_SNOP);            // Reset Radio Pointer
}

// *************************************************************************************************
// @fn          ReadSingleReg
// @brief       Read byte from register.
// @param       none
// @return      none
// *************************************************************************************************
unsigned char ReadSingleReg(unsigned char addr)
{
    unsigned char x;
    u16 int_state;

    ENTER_CRITICAL_SECTION(int_state);

    RF1AINSTR1B = (addr | RF_REGRD);
    x = RF1ADOUT1B;

    EXIT_CRITICAL_SECTION(int_state);

    return x;
}

// *************************************************************************************************
// @fn          WriteSingleReg
// @brief       Write byte to register.
// @param       none
// @return      none
// *************************************************************************************************
void WriteSingleReg(unsigned char addr, unsigned char value)
{
    volatile unsigned int i;
    u16 int_state;

    ENTER_CRITICAL_SECTION(int_state);

    while (!(RF1AIFCTL1 & RFINSTRIFG)) ;           // Wait for the Radio to be ready for the next
                                                   // instruction

    RF1AINSTRW = ((addr | RF_REGWR) << 8) + value; // Send address + Instruction
    while (!(RFDINIFG & RF1AIFCTL1)) ;

    i = RF1ADOUTB;                                 // Reset RFDOUTIFG flag which contains status
                                                   // byte

    EXIT_CRITICAL_SECTION(int_state);
}

// *************************************************************************************************
// @fn          ReadBurstReg
// @brief       Read sequence of bytes from register.
// @param       none
// @return      none
// *************************************************************************************************
void ReadBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count)
{
    unsigned int i;
    u16 int_state;

    ENTER_CRITICAL_SECTION(int_state);

    while (!(RF1AIFCTL1 & RFINSTRIFG)) ;     // Wait for the Radio to be ready for next instruction
    RF1AINSTR1B = (addr | RF_REGRD);         // Send address + Instruction

    for (i = 0; i < (count - 1); i++)
    {
        while (!(RFDOUTIFG & RF1AIFCTL1)) ;  // Wait for the Radio Core to update the RF1ADOUTB reg
        buffer[i] = RF1ADOUT1B;              // Read DOUT from Radio Core + clears RFDOUTIFG
        // Also initiates auo-read for next DOUT byte
    }
    buffer[count - 1] = RF1ADOUT0B;          // Store the last DOUT from Radio Core

    EXIT_CRITICAL_SECTION(int_state);
}

// *************************************************************************************************
// @fn          WriteBurstReg
// @brief       Write sequence of bytes to register.
// @param       none
// @return      none
// *************************************************************************************************
void WriteBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count)
{
    // Write Burst works wordwise not bytewise - bug known already
    unsigned char i;
    u16 int_state;

    ENTER_CRITICAL_SECTION(int_state);

    while (!(RF1AIFCTL1 & RFINSTRIFG)) ;               // Wait for the Radio to be ready for next
                                                       // instruction
    RF1AINSTRW = ((addr | RF_REGWR) << 8) + buffer[0]; // Send address + Instruction

    for (i = 1; i < count; i++)
    {
        RF1ADINB = buffer[i];                          // Send data
        while (!(RFDINIFG & RF1AIFCTL1)) ;             // Wait for TX to finish
    }
    i = RF1ADOUTB;                                     // Reset RFDOUTIFG flag which contains status
                                                       // byte

    EXIT_CRITICAL_SECTION(int_state);
}

// *************************************************************************************************
// @fn          WritePATable
// @brief       Write data to power table
// @param       unsigned char value             Value to write
// @return      none
// *************************************************************************************************
void WritePATable(unsigned char value)
{
    unsigned char readbackPATableValue = 0;
    u16 int_state;

    ENTER_CRITICAL_SECTION(int_state);

    while (readbackPATableValue != value)
    {
        while (!(RF1AIFCTL1 & RFINSTRIFG)) ;
        RF1AINSTRW = 0x7E00 + value; // PA Table write (burst)

        while (!(RF1AIFCTL1 & RFINSTRIFG)) ;
        RF1AINSTRB = RF_SNOP;        // reset pointer

        while (!(RF1AIFCTL1 & RFINSTRIFG)) ;
        RF1AINSTRB = 0xFE;           // PA Table read (burst)

        while (!(RF1AIFCTL1 & RFDINIFG)) ;
        RF1ADINB = 0x00;             //dummy write

        while (!(RF1AIFCTL1 & RFDOUTIFG)) ;
        readbackPATableValue = RF1ADOUT0B;

        while (!(RF1AIFCTL1 & RFINSTRIFG)) ;
        RF1AINSTRB = RF_SNOP;
    }

    EXIT_CRITICAL_SECTION(int_state);
}

